;-------------------------------------------------------------------------------
format ELF64 executable 3
entry start

RTLD_LAZY = 1

SDL_KEYDOWN = 2
SDL_INIT_VIDEO = 0x00000020
SDL_OPENGL = 0x00000002
SDL_NOFRAME = 0x00000020
SDL_GL_DOUBLEBUFFER = 5

GL_FRAGMENT_SHADER = 0x8B30

DEBUG = 0

macro emit [param] { param }
;-------------------------------------------------------------------------------
include 'import64.inc'
interpreter '/lib64/ld-linux-x86-64.so.2'
needed 'libdl.so.2'
import dlopen,dlsym
;-------------------------------------------------------------------------------
segment readable executable

start:
    sub rsp,2048
    ; define local variables
    emit\
        < log equ rsp >,< event equ rsp+1024 >,< printf equ rsp+1088 >,\
        < SDL_PollEvent equ rsp+1096 >,< SDL_GetTicks equ rsp+1104 >,< SDL_GL_SwapBuffers equ rsp+1112 >,\
        < glRecti equ rsp+1120 >,< glTexCoord1f equ rsp+1128 >
    mov r13,[dlsym]
if DEBUG = 1
    ; load printf
    emit < xor edi,edi >,< mov rsi,g_str_printf >,< call r13 >,< mov [printf],rax >
end if
    ; load SDL library
    emit < mov rdi,g_str_libsdl >,< mov esi,RTLD_LAZY >,< call [dlopen] >,< mov r12,rax >
    ; call SDL_Init
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_Init >,< call r13 >
    emit < mov edi,SDL_INIT_VIDEO >,< call rax >
    ; call SDL_GL_SetAttribute
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_GL_SetAttribute >,< call r13 >
    emit < mov edi,SDL_GL_DOUBLEBUFFER >,< mov esi,1 >,< call rax >
    ; call SDL_GL_LoadLibrary
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_GL_LoadLibrary >,< call r13 >
    emit < xor edi,edi >,< call rax >
    ; call SDL_SetVideoMode
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_SetVideoMode >,< call r13 >
    emit < mov edi,800 >,< mov esi,800 >,< xor edx,edx >,< mov ecx,SDL_OPENGL+SDL_NOFRAME >,< call rax >
    ; load needed functions
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_PollEvent >,< call r13 >,< mov [SDL_PollEvent],rax >
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_GetTicks >,< call r13 >,< mov [SDL_GetTicks],rax >
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_GL_SwapBuffers >,< call r13 >,< mov [SDL_GL_SwapBuffers],rax >
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_GL_GetProcAddress >,< call r13 >,< mov rbx,rax >
    emit < mov rdi,g_str_glRecti >,< call rbx >,< mov [glRecti],rax >
    emit < mov rdi,g_str_glTexCoord1f >,< call rbx >,< mov [glTexCoord1f],rax >
    ; create program
    emit < mov rdi,g_str_glCreateShaderProgramv >,< call rbx >
    emit < mov edi,GL_FRAGMENT_SHADER >,< mov esi,1 >,< mov rdx,g_src_fs_ptr >,< call rax >,< mov r15d,eax >
    ; use program
    emit < mov rdi,g_str_glUseProgram >,< call rbx >
    emit < mov edi,r15d >,< call rax >
if DEBUG = 1
    ; print GLSL info log
    emit < mov rdi,g_str_glGetProgramInfoLog >,< call rbx >
    emit < mov edi,r15d >,< mov esi,1024 >,< xor edx,edx >,< lea rcx,[log] >,< call rax >
    emit < mov rdi,g_str_log >,< lea rsi,[log] >,< call qword [printf] >
end if
      .main_loop:
    ; process window events
    emit < lea rdi,[event] >,< call qword [SDL_PollEvent] >
    cmp byte [event],SDL_KEYDOWN
    je .main_loop_end
    ; get time
    call qword [SDL_GetTicks]
    emit < cvtsi2ss xmm0,eax >,< call qword [glTexCoord1f] >
    ; draw
    emit < mov edi,-1 >,< mov esi,-1 >,< mov edx,1 >,< mov ecx,1 >,< call qword [glRecti] >
    ; swap
    call qword [SDL_GL_SwapBuffers]
    jmp .main_loop
      .main_loop_end:
    ; call SDL_Quit
    emit < mov rdi,r12 >,< mov rsi,g_str_SDL_Quit >,< call r13 >,< call rax >
    ; terminate process
    emit < mov eax,60 >,< xor edi,edi >,syscall
;-------------------------------------------------------------------------------
align 1
g_src_fs:
db  'float t;'
db  'void main(){'
db      't=.001*gl_TexCoord[0].s;'
db      'vec2 p=-1+2*gl_FragCoord.xy/vec2(800);'
db      'float a=atan(p.y,p.x);'
db      'p.x=cos(a+t);'
db      'p.y=sin(a+t);'
db      'a=atan(p.y,p.x);'
db      'gl_FragColor=vec4(0,smoothstep(-.2,0,a)-smoothstep(0,.2,a),0,1);'
db  '}',0

g_str_libsdl db 'libSDL-1.2.so.0',0
g_str_SDL_Init db 'SDL_Init',0
g_str_SDL_SetVideoMode db 'SDL_SetVideoMode',0
g_str_SDL_PollEvent db 'SDL_PollEvent',0
g_str_SDL_GetTicks db 'SDL_GetTicks',0
g_str_SDL_GL_LoadLibrary db 'SDL_GL_LoadLibrary',0
g_str_SDL_GL_GetProcAddress db 'SDL_GL_GetProcAddress',0
g_str_SDL_GL_SetAttribute db 'SDL_GL_SetAttribute',0
g_str_SDL_GL_SwapBuffers db 'SDL_GL_SwapBuffers',0
g_str_glCreateShaderProgramv db 'glCreateShaderProgramv',0
g_str_glRecti db 'glRecti',0
g_str_glUseProgram db 'glUseProgram',0
g_str_glTexCoord1f db 'glTexCoord1f',0
g_str_SDL_Quit db 'SDL_Quit',0
if DEBUG = 1
g_str_printf db 'printf',0
g_str_glGetProgramInfoLog db 'glGetProgramInfoLog',0
g_str_log db '%s',10,0
end if

align 8
g_src_fs_ptr dq g_src_fs
;-------------------------------------------------------------------------------
